package com.xing.binbackend.http.webclient;

import com.xing.binbackend.http.RestMethod;
import com.xing.binbackend.http.RestfulParameters;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.netty.http.client.HttpClient;

import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Optional;


@Component
@Slf4j
public class WebClientRest {
    private final WebClient webClient;

    /**
     * 配置方式         适用场景            代码示例
     * 信任所有证书       测试环境            InsecureTrustManagerFactory.INSTANCE
     * 自定义信任库       生产环境            trustManager(new File("truststore.jks"), "pwd")
     * 系统默认信任库      标准环境            不显式设置trustManager
     */
    public WebClientRest() throws Exception {
        this.webClient = createWebClient(true);
    }

    public static WebClient createWebClient(boolean isProd) throws Exception {
        SslContext sslContext = isProd ? buildProdSSLContext() : buildTestSSLContext();
        HttpClient httpClient =
                HttpClient.create().secure(spec -> spec.sslContext(sslContext).handshakeTimeout(Duration.ofSeconds(10))).responseTimeout(Duration.ofSeconds(30));
        return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();
    }

    // 测试环境使用
    private static SslContext buildTestSSLContext() throws Exception {
        return SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).protocols("TLSv1.2").build();
    }

    // 生产环境使用
    private static SslContext buildProdSSLContext() throws Exception {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
        tmf.init((KeyStore) null); // 加载系统默认信任库
    //  .sslProvider(SslProvider.auto()) // 自动选择最佳SSL实现

        return SslContextBuilder.forClient().trustManager(tmf).protocols("TLSv1.2", "TLSv1.3").sslProvider(SslProvider.OPENSSL).build();
    }

    public <T> Optional<T> sendRequest(String url, RestfulParameters parameters,
                                       RestMethod method, Class<T> responseType) {
        try {
            return method == RestMethod.GET ? handleGetRequest(url, parameters, responseType) :
                    handlePostRequest(url, parameters, responseType);
        } catch (WebClientResponseException e) {
            log.error("HTTP请求失败，状态码：{}，响应体：{}", e.getRawStatusCode(), e.getResponseBodyAsString());
            return Optional.empty();
        } catch (Exception e) {
            log.error("请求处理异常：{}", e.getMessage());
            return Optional.empty();
        }
    }

    private <T> Optional<T> handleGetRequest(String url, RestfulParameters parameters,
                                             Class<T> responseType) {
        return webClient.get().uri(uriBuilder -> {
            uriBuilder.path(url);
            parameters.getParamMap().forEach(uriBuilder::queryParam);
            return uriBuilder.build();
        }).headers(headers -> headers.setAll(parameters.getHeaderMap())).retrieve().bodyToMono(responseType).blockOptional(Duration.ofSeconds(30));
    }

    private <T> Optional<T> handlePostRequest(String url, RestfulParameters parameters,
                                              Class<T> responseType) {
        return webClient.post().uri(url).headers(headers -> headers.setAll(parameters.getHeaderMap())).bodyValue(parameters.getParamMap()).retrieve().bodyToMono(responseType).blockOptional(Duration.ofSeconds(30));
    }

    // PUT请求处理方法示例
    private <T> Optional<T> handlePutRequest(String url, RestfulParameters parameters,
                                             Class<T> responseType) {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        parameters.getParamMap().forEach(formData::add);
        return webClient.put().uri(url).headers(h -> h.setAll(parameters.getHeaderMap())).contentType(MediaType.APPLICATION_FORM_URLENCODED).body(BodyInserters.fromFormData(formData)).retrieve().bodyToMono(responseType).blockOptional();
    }

    // DELETE请求处理方法示例
    private Optional<Void> handleDeleteRequest(String url, RestfulParameters parameters) {
        return webClient.delete().uri(url).headers(h -> h.setAll(parameters.getHeaderMap())).retrieve().toBodilessEntity().blockOptional().map(e -> null);
    }

    // SSL信任管理器（测试环境专用）
    private static class TrustAllX509TrustManager implements X509TrustManager {
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

}
